package session

import (
	"codego/itools/demo/gobatis-plus/orm"
	"codego/itools/demo/gobatis-plus/utils"
	"codego/itools/demo/gobatis-plus/xml_parser"
	"database/sql"
	"errors"
	"github.com/patrickmn/go-cache"
	"strings"
	"time"
)





type SqlSession struct {
	Db 			orm.OrmInfuraInter      //实现此接口的ORM组件
	//IsCache 	bool					//是否启用缓存
	//CacheTime   int64					//缓存时间
	//CacheType   string    				//缓存类型
	Cache       *cache.Cache
}

var sqlSession *SqlSession

//打开数据库连接
func(fac *SqlSessionFactory)OpenSession(ormName string,dsType DbType,dbfunc DbFunc)*SqlSession{
	fac.once.Do(func() {
		orm := orm.GetOrm(ormName)
		dbProperty,ok := fac.DbM[string(dsType)][string(dbfunc)]
		if !ok{
			panic("db property error")
		}
		inter := orm(dbProperty.UserName, dbProperty.Password, dbProperty.Url, dbProperty.DataBase)
		sqlSession=&SqlSession{Db: inter}
		c := cache.New(30, 10)
		sqlSession.Cache=c
	})
	return sqlSession
}

type CachePrority struct {
	IsCache 		bool
	CacheTime 		int64
	CacheType 		utils.CacheType
}

type OptionFunc func(prority *CachePrority)

func WithIsCache(isCache bool)OptionFunc{
	return func(p *CachePrority){
		p.IsCache=isCache
	}
}

func WithCacheTime(cacheTime int64)OptionFunc{
	return func(p *CachePrority) {
		p.CacheTime=cacheTime
	}
}

func WithCacheType(cacheType utils.CacheType)OptionFunc{
	return func(p *CachePrority) {
		p.CacheType=cacheType
	}
}

func (s *SqlSession)FindOne(res interface{},method string,params []interface{},options... OptionFunc)error{
	cp:=new(CachePrority)

	for _,option:=range options{
		option(cp)
	}

	ms:=strings.Split(method,".")
	if len(ms)!=2{
		return errors.New("method error")
	}

	entity := xml_parser.M.EntityMap[ms[0]]
	sqlStr := entity.MethodMap[ms[1]].InnerSql
	resultType:=entity.MethodMap[ms[1]].ResultType

	//判断是否开启缓存
	rows:=&sql.Rows{}
	if cp.IsCache==true && cp.CacheType==utils.NativeCache {
		cacheData, b := s.Cache.Get(method)
		if b {
			rows = cacheData.(*sql.Rows)
		}else{
			rows=s.Db.Query(sqlStr,params)
			s.Cache.Set(method,rows,time.Second*time.Duration(cp.CacheTime))
		}
	}else{
		rows=s.Db.Query(sqlStr,params)
		s.Cache.Set(method,rows,time.Second*time.Duration(cp.CacheTime))
	}
	resProc, ok :=utils.ResSetProcMap[utils.ResultType(resultType)]
	if !ok {
		return errors.New("No exec result type proc, result type:" + resultType)
	}

	err := resProc(rows, res)
	rows.Close()
	if nil != err {
		return err
	}
	return nil
}

func (s *SqlSession) FindList(res interface{},method string,params []interface{},options... OptionFunc)error{
	cp:=new(CachePrority)

	for _,option:=range options{
		option(cp)
	}

	ms:=strings.Split(method,".")
	if len(ms)!=2{
		return errors.New("method error")
	}

	entity := xml_parser.M.EntityMap[ms[0]]
	sqlStr := entity.MethodMap[ms[1]].InnerSql
	resultType:=entity.MethodMap[ms[1]].ResultType

	rows := s.Db.Query(sqlStr, params)

	resProc := utils.ResSetProcMap[utils.ResultType(resultType)]
	if resProc==nil{
		return errors.New("proc rows func is nil")
	}
	err := resProc(rows, res)
	rows.Close()
	if err!=nil{
		return err
	}
	return nil
}